package com.apache.passport.service.plugins;

import com.alibaba.fastjson.JSONObject;
import com.apache.api.manager.PluginConnector;
import com.apache.api.vo.ParamsVo;
import com.apache.cache.util.Validator;
import com.apache.database.constant.SystemTools;
import com.apache.database.db.IDao;
import com.apache.database.model.MethodParam;
import com.apache.passport.common.DesUtils;
import com.apache.passport.common.LoginCacheErrTimer;
import com.apache.passport.common.PassPortConst;
import com.apache.passport.entity.*;
import com.apache.passport.jwt.CommonResponse;
import com.apache.passport.jwt.Constant;
import com.apache.passport.jwt.JwtUtil;
import com.apache.tools.DateUtils;
import com.apache.tools.MD5Utils;
import com.apache.tools.StrUtil;

import java.util.Date;
import java.util.List;

/**
 * description:  用户登录插件
 *
 * author dyhou 创建时间：2016-12-19
 */
public class LoginUserForJwtPlugin extends SuperPluginConnector {

//    protected IDao uctUserDao;

    protected IDao blackRosterDao;

//    public void setUctUserDao(IDao uctUserDao) {
//        this.uctUserDao = uctUserDao;
//    }

    /**
     * TODO 用户密码校验
     */
    public Object execute(ParamsVo vo) throws Exception {
        String remoteIp = Validator.getDefaultStr(String.valueOf(vo.getParams("remoteIp")),
                String.valueOf(vo.getParams("addressIP")));
        CommonResponse res = new CommonResponse();
        UctUser uctUser = (UctUser) vo.getObj();
        if (null == uctUser) {
            uctUser = new UctUser();
            uctUser.setUserEname(String.valueOf(vo.getParams("userEname")));
            uctUser.setUserPass(String.valueOf(vo.getParams("userPass")));
            uctUser.setOrgEname(String.valueOf(vo.getParams("orgEname")));
            vo.setObj(uctUser);
        }
        //登录前首先从数据库中查询下该用户是否存在于黑名单中
        BlackRoster br = (BlackRoster) getBrInfoByIp(remoteIp, uctUser.getUserEname());//验证是否在黑名单中
        if (null != br) {
            res.setCode(Constant.RESCODE_BLOCK);
            res.setMsg("用户已被列入黑名单");
            return res;
        }
        return innerLogin(vo, remoteIp);
    }

    /**
     * description:  本系统登录
     */
    private Object innerLogin(ParamsVo vo, String remoteIp) throws Exception {

        UctUser uctUser = (UctUser) vo.getObj();
        CommonResponse res = new CommonResponse();
        if (Validator.isNull(uctUser.getUserEname())) {
            res.setCode(Constant.RESCODE_EXCEPTION);
            res.setMsg("用户名不能为空");
            return res;
        }
        if (Validator.isNull(uctUser.getUserPass())) {
            res.setCode(Constant.RESCODE_EXCEPTION);
            res.setMsg("密码不能为空");
            return res;
        }
        String synFlag = SystemTools.getInstance().getValue("synFlag");
        //查询用户是否存在
        UctUser obj = (UctUser) getInfoByEname(vo);
        //判断用户是否存在
        if (!Validator.isEmpty(obj)) {
            String userEname = obj.getUserEname();
            String upass = uctUser.getUserPass();
            //判断密码是否正确
            if (obj.getUserPass().equalsIgnoreCase(upass)) {
                //虽然密码正确,但是需要判断下之前缓存中是否存在该用户的登陆错误信息,如果存在,则依然返回等待
                LonErrToken tokenE = (LonErrToken) SystemTools.getInstance()
                        .getCache("loginErrToken").getCacheCloneByKey(remoteIp + userEname);
                if (!Validator.isEmpty(tokenE)) {
                    if(LoginCacheErrTimer.getInstance().checkErrToken(remoteIp,obj.getUserEname())){
                        String count = tokenE.getLoginCount();
                        int c = Integer.parseInt(count);
                        if ("3".equals(tokenE.getLoginCount()) || "6".equals(tokenE.getLoginCount())
                                || "9".equals(tokenE.getLoginCount()) || c > 12) {
                            //如果错误次数等于以上几个参数,也同样需要校验下时间是否已经过期,防止时间已过,且登录密码正确,却一直没有更新缓存
                            LoginCacheErrTimer.getInstance().setErrToken(vo, remoteIp, null, obj);
                            res.setCode(Constant.RESCODE_LOCK);
                            res.setMsg("用户已被锁定");
                            return res;
                        }
                    }
                }
                Integer userStatus = obj.getUserStatus();//用户状态(-1:删除状态,0:停用,1:启用)
                if (Validator.isEmpty(userStatus)) {
                    userStatus = 10000;//自定值,防止用户状态未设置
                }
                if (userStatus == -1) {
                    res.setCode(Constant.RESCODE_EXCEPTION);
                    res.setMsg("用户已留痕删除,请联系系统管理员");
                    return res;
                }
                if (userStatus == 0) {
                    res.setCode(Constant.RESCODE_EXCEPTION);
                    res.setMsg("用户已停用,请联系系统管理员");
                    return res;
                }
                if (StrUtil.isNotNull(uctUser.getOrgEname()))
                    obj.setOrgEname(uctUser.getOrgEname());
                Token token = new Token();
                token.setLoginTime(DateUtils.format(new Date(), "yyyy-MM-dd HH:mm"));
                String clientid = String.valueOf(vo.getParams("clientid"));
                String code = MD5Utils.MD5(clientid + Validator.generate());

                if (StrUtil.isNotNull(uctUser.getOrgEname()))
                    obj.setOrgEname(uctUser.getOrgEname());
                String subject = JwtUtil.newInstance().generalSubject(obj);
                String auds = getVoBySysEname(clientid, remoteIp);
                if (Validator.isNull(auds)) {
                    res.setCode(Constant.RESCODE_EXCEPTION);
                    res.setMsg("没有被授权使用");
                    return res;
                }
                String tokenId = JwtUtil.newInstance()
                        .uniCreateJwt(Constant.JWT_ID, code, auds, Constant.JWT_TTL, subject);
                if (Validator.isNull(tokenId)) {
                    res.setCode(Constant.RESCODE_EXCEPTION);
                    res.setMsg("证书签名失败");
                    return res;
                }
                //					JwtUtil.newInstance().createJWT(Constant.JWT_ID, subject, auds, Constant.JWT_TTL);
                String desEname = DesUtils.getInstance().encrypt(userEname);
                JSONObject jo = new JSONObject();
                jo.put("token", tokenId);
                jo.put("code", code);
                jo.put("domain", SystemTools.getInstance().getValue("sys_domain"));
                //jo.put("bjcaUserid", Validator.getDefaultStr(obj.getBjcaUserid(), ""));
                jo.put("userEname", userEname);
                res.setCode(Constant.RESCODE_SUCCESS);
                res.setData(jo.toString());
                //如果登录成功后,清空错误记录缓存
                SystemTools.getInstance().getCache("loginErrToken")
                        .removeCacheObject(remoteIp + userEname);

                token.setTokenId(tokenId);
                token.setUserEname(desEname);
                token.setUserCname(obj.getUserCname());
                token.setEmail(DesUtils.getInstance().encrypt(obj.getEmail()));
                token.setMobile(DesUtils.getInstance().encrypt(obj.getMobile()));
                token.setUserId(code);
                LoginInfo loginInfo = null;
                if (null == vo.getParams("loginInfo")) {
                    loginInfo = new LoginInfo();
                    loginInfo.setLgnLastipaddress(remoteIp);
                    loginInfo.setUserEname(userEname);
                    loginInfo.setLgnLasttime(DateUtils.Now.fmt_yyyyMMdd_HHmmss());
                    loginInfo.setSysEname(clientid);
                } else {
                    loginInfo = (LoginInfo) vo.getParams("loginInfo");
                    loginInfo.setTokenId(tokenId);
                }
                token.setLoginInfo(loginInfo);
                //如果登录成功后,清空错误记录缓存
                PassPortConst.detLonErrToken(remoteIp, obj.getUserEname());
                //如果属于单态,使用单态只应用在登录场景,如果在飞单态情况下登录成功,
                //其修改了配置文件,使用单态,则无法启到单态登录的效果,因为此功能只添加至登录操作中
                PassPortConst.setToken("1".equals(synFlag) ? true : false, tokenId, token);
                return res;
            } else {
                LoginCacheErrTimer.getInstance().setErrToken(vo, remoteIp, null, obj);
            }
        } else {
            LoginCacheErrTimer.getInstance().setErrToken(vo, remoteIp, null, obj);
        }
        res.setCode(Constant.RESCODE_NOEXIST);
        res.setMsg("用户不存在或密码错误");
        return res;
    }

    /**
     * description:  根据ename,手机号,邮箱查询用户信息
     */
    /*public Object getInfoByEname(ParamsVo<UctUser> vo) {
        UctUser user = vo.getObj();
        String userEname = user.getUserEname();
        if (Validator.isNull(userEname)) {
            return null;
        }
        String sql = uctUserDao.getSql(3);// from UctUser where userEname :=userEname
        String mobileLogin = SystemTools.getInstance().getValue("mobileLogin");
        String emailLogin = SystemTools.getInstance().getValue("emailLogin");
        String orgEname = user.getOrgEname();

        MethodParam param = new MethodParam("ByUserEname", "", uctUserDao.getSql(3),
                "com.apache.passport.entity.UctUser");
        param.setParams("userEname", userEname);
        if (Validator.isNotNull(orgEname)) {
            param.setParams("orgEname", orgEname);
        }
        if ("1".equals(mobileLogin)) {
            param.setParams("mobile", userEname);
            sql += "or mobile :=userEname ";
        }
        if ("1".equals(emailLogin)) {
            param.setParams("email", userEname);
            sql += "or email :=userEname ";
        }
        param.setSqlStr(sql);
        List list = uctUserDao.select(param);
        if (Validator.isEmpty(list))
            return null;
        return list.get(0);
    }*/

    /**
     * description:  根据IP及用户名获取黑名单
     *
     * @return
     */
    public Object getBrInfoByIp(String reqIp, String userEname) {
        //只验证用户名
        String sql = blackRosterDao.getSql(4);
        if (!Validator.isNull(reqIp)) {
            sql += " and brIpaddress :=brIpaddress ";
        }
        MethodParam param = new MethodParam("ByIpOrUserEname", "", sql,
                BlackRoster.class.getName());
        param.setParams("brIpaddress", reqIp);
        param.setParams("brAccount", userEname);
        return blackRosterDao.selectSingle(param);
    }

    public void setBlackRosterDao(IDao blackRosterDao) {
        this.blackRosterDao = blackRosterDao;
    }

    /**
     * description:  根据系统名称查询系统访问权限
     *
     * @param sysEname
     */
    private String getVoBySysEname(String sysEname, String ip) {
        if (Validator.isNull(sysEname))
            return "";
        //不需要认证的系统
        String goOn = SystemTools.getInstance().getValue("otherGO");
        if (goOn.equalsIgnoreCase(sysEname)) {
            return goOn;
        }
        MethodParam param = new MethodParam("BySysEname", "", "", OutwardSys.class.getName());
        param.setParams("sysEname", sysEname);
        Object obj = blackRosterDao.selectSingle(param);
        //操作之前首先查看是否存在操作权限
        OutwardSys outwardSys = (OutwardSys) obj;
        if (Validator.isEmpty(outwardSys)) {
            return "";
        }
        if ("1".equals(outwardSys.getSysStatus())) {
            return "";
        }
        String aud = outwardSys.getSysEname();
        if ("1".equals(outwardSys.getSysInterface())) {//是否sso
            param = new MethodParam("ByProperty", "", "", OutwardSys.class.getName());
            param.setParams("sysInterface", "1");
            param.setParams("sysStatus", "0");
            List list = blackRosterDao.select(param);
            if (!Validator.isEmpty(list)) {
                for (int i = 0; i < list.size(); i++) {
                    OutwardSys os = (OutwardSys) list.get(i);
                    if (!outwardSys.getSysEname().equals(os.getSysEname()))
                        aud += "," + os.getSysEname();
                }
            }
        }
        return aud;

    }
}


